#include <functional>
#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>

std::mutex g_mtx{};
std::timed_mutex g_tmtx{};
int g_nSharedData{};
std::shared_mutex g_smtx{};

/**
 * @brief 基础用法
 */
void UniqueLockBasic()
{
    auto func = []()
    {
        std::unique_lock<std::mutex> locks(g_mtx); // 构造时自动上锁
        g_nSharedData++; // 离开作用域时自动解锁
    };

    std::thread t1{func};
    std::thread t2{func};
    t1.join();
    t2.join();
    std::cout << "Result:" << g_nSharedData << std::endl;
}

/**
 * @brief 延迟上锁
 */
void UniqueLockDelay()
{
    auto func = []()
    {
        std::unique_lock lock{g_mtx, std::defer_lock}; // 延迟上锁
        std::cout << "Doing something without lock" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(5));

        lock.lock();
        g_nSharedData++;
        std::cout << "Result:" << g_nSharedData << std::endl;

        lock.unlock(); // 自动解锁

        std::cout << "Doing something without lock" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(5));
        lock.lock();
        g_nSharedData++; // 出作用域自动解锁
        std::cout << "Result:" << g_nSharedData << std::endl;
    };
    // g_mtx.lock(); 如果继续对互斥量进行上锁或者解锁会出现未定义的行为

    std::thread t1{func};
    std::thread t2{func};
    t1.join();
    t2.join();
}

/**
 * @brief 尝试上锁
 */
void UniqueLockTry()
{
    auto func = []()
    {
        std::unique_lock lock{g_mtx, std::try_to_lock}; // 尝试上锁
        if (lock.owns_lock())
        {
            // 成功获取锁
            g_nSharedData++;
            std::cout << "Result:" << g_nSharedData << std::endl;
        }
        else
        {
            // 未能获取锁
            std::cout << "Doing something without lock" << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(5));
        }
    };

    std::thread t1{func};
    std::thread t2{func};
}

/**
 * @brief 定时上锁
 */
void UniqueLockTimed()
{
    auto func = []()
    {
        std::unique_lock lock{g_tmtx , std::chrono::milliseconds(100)};
        if (lock.owns_lock())
        {
            g_nSharedData++;
            std::cout << "Result:" << g_nSharedData << std::endl;
        }
        else
        {
            std::cout << "Doing something without lock" << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(5));
        }
    };

    std::thread t1{func};
    std::thread t2{func};
}

/**
 * @brief 转移所有权
 */
void UniqueLockTransfer()
{
    auto func = []()
    {
        std::unique_lock<std::mutex> lock(g_mtx);
        return lock;
    };

    std::unique_lock lock{func()}; // 接受所有权
}

/**
 * @brief 读写锁的基本用法
 */
void SharedLockBasic()
{
    auto FunRead = []()
    { // 读取操作
        std::shared_lock lock{g_smtx}; // 获取共享锁
        std::cout << "Reader" << g_nSharedData << " Id:" << std::this_thread::get_id() << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    };

    auto FunWrite = []()
    { // 写操作
        std::unique_lock lock{g_smtx}; // 获取独占锁
        std::cout << "Writer：" << " Id:" << std::this_thread::get_id() << std::endl;
        g_nSharedData++;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    };

    std::jthread t1{FunRead}; // 读操作
    std::jthread t2{FunRead}; // 读操作
    std::jthread t3{FunRead}; // 读操作
    std::jthread t4{FunWrite}; // 写操作
}

void RecursiveLockBasic()
{
    std::recursive_mutex rmtx;
    int count = 0;

    // 递归函数，演示同一线程多次加锁
    std::function<void(int)> func = [&](int depth)
    {
        std::lock_guard<std::recursive_mutex> lock(rmtx);
        std::cout << "Depth: " << depth << ", Count: " << ++count << std::endl;
        if (depth > 0)
        {
            func(depth - 1);
        }
    }; // 不允许用auto推断递归自身引用

    std::thread t1([&](){ func(3); });
    std::thread t2([&](){ func(2); });
    t1.join();
    t2.join();
}

int main()
{
    // UniqueLockBasic(); // 基本用法
    // UniqueLockDelay(); // 延迟上锁
    // UniqueLockTry(); // 尝试上锁
    // UniqueLockTimed(); // 定时上锁
    // SharedLockBasic(); // 读写锁
    // RecursiveLockBasic(); // 递归锁的基本用法

    return 0;

}
